package com.myibatis.aop;

import com.myibatis.annotation.Arguments;
import com.myibatis.annotation.Sql;
import com.myibatis.util.SimpleDaoPage;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: wangchen
 * Date: 16-5-30
 * Time: 下午1:37
 * To change this template use File | Settings | File Templates.
 */
//@Component
//@Aspect
public class DaoHandler {
    private static final Logger logger = Logger.getLogger(DaoHandler.class);
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    @Pointcut("execution(* com..*.dao.*Dao.*(..))")
    private void selectCutMethod() {
    }

    @SuppressWarnings("unchecked")
    @Around("selectCutMethod()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();  //参数
        Object target = pjp.getTarget();//目标对象
        String methodName = pjp.getSignature().getName();
        Class [] classes = null;
        Method method = null;
        if(args !=null && args.length>0){
            classes = new Class[args.length];
            for(int i=0;i< args.length;i++){
                classes[i] = args[i].getClass();
            }
        }
        if(classes!=null){
            method  = target.getClass().getMethod(methodName,classes);
        }else{
            method  = target.getClass().getMethod(methodName);
        }

        // 返回结果
        Object returnObj = null;
        // SQL模板
        String templateSql = null;
        // SQL模板参数
        Map<String, Object> sqlParamsMap = new HashMap<String, Object>();
        // 分页参数
        SimpleDaoPage pageSetting = new SimpleDaoPage();
        // Step.1装载SQL模板，所需参数

        templateSql = installDaoMetaData(pageSetting, method, sqlParamsMap, args);

        Object o = pjp.proceed();
        return o;
    }

    /**
     * 装载SQL模板参数
     *
     * @param pageSetting
     *
     * @param method
     * @param sqlParamsMap
     *            返回(装载模板参数)
     * @param args
     * @return templateSql(@SQL标签的SQL)
     * @throws Exception
     */
    private String installDaoMetaData(SimpleDaoPage pageSetting, Method method, Map<String, Object> sqlParamsMap, Object[] args) throws Exception {
        String templateSql = null;
        // 如果方法参数大于1个的话，方法必须使用注释标签Arguments
        boolean arguments_flag = method.isAnnotationPresent(Arguments.class);
        if (arguments_flag) {
            // [1].获取方法的参数标签
            Arguments arguments = method.getAnnotation(Arguments.class);
            logger.debug("@Arguments------------------------------------------" + Arrays.toString(arguments.value()));
            if (arguments.value().length > args.length) {
                // 校验机制-如果注释标签参数数目大于方法的参数，则抛出异常
                throw new Exception("[注释标签]参数数目，不能大于[方法参数]参数数目");
            }
            // step.2.将args转换成键值对，封装成Map对象
            int args_num = 0;
            for (String v : arguments.value()) {
                // update-begin--Author:fancq Date:20140102 for：支持多数据分页
                if (v.equalsIgnoreCase("page")) {
                    pageSetting.setPage(Integer.parseInt(args[args_num].toString()));
                }
                if (v.equalsIgnoreCase("rows")) {
                    pageSetting.setRows(Integer.parseInt(args[args_num].toString()));
                }
                // update-end--Author:fancq Date:20140102 for：支持多数据分页
                sqlParamsMap.put(v, args[args_num]);
                args_num++;
            }
        } else {
            // 如果未使用[参数标签]
            if (args != null && args.length > 1) {
                throw new Exception("方法参数数目>=2，方法必须使用注释标签@Arguments");
            } else if (args != null && args.length == 1) {
                // step.2.将args转换成键值对，封装成Map对象
                //sqlParamsMap.put(MiniDaoConstants.SQL_FTL_DTO, args[0]);
            }

        }

        // [2].获取方法的SQL标签
        if (method.isAnnotationPresent(Sql.class)) {
            Sql sql = method.getAnnotation(Sql.class);
            // 如果用户采用自定义标签SQL，则SQL文件无效
            if (StringUtils.isNotEmpty(sql.value())) {
                templateSql = sql.value();
            }
            logger.debug("@Sql------------------------------------------" + sql.value());
        }
        return templateSql;
    }
}
